#define __STDC_WANT_LIB_EXIT1__ 1 // 启用C11标准支持
#define _XOPEN_SOURCE // 启用拓展支持，如POSIX的格式化时间函数

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#include <wchar.h>
#include <assert.h>
#include <errno.h>
#include <time.h>
#include <locale.h>
#include <sys/timeb.h>
#include <sys/stat.h>

#ifdef __STDC__

#include <sys/time.h>
#include <stdatomic.h>
#include <unistd.h>

#endif
#ifdef _WIN32

#include <io.h>
#include <conio.h>
#include <windows.h>

#endif

#include "tinycthread.h"

#if defined(_WIN32) && defined(__MINGW32__)
#define ENCODING_UTF_8 setlocale(LC_ALL, "chs") // mingw只有GBK
#else
#define ENCODING_UTF_8 setlocale(LC_ALL, "zh_CN.UTF-8")
#endif

#ifdef linux
#define PRINTF_STR(format, ...) printf(format, ##__VA_ARGS__)
#else
#define PRINTF_STR(format, ...) wprintf(format, ##__VA_ARGS__)
#endif

#define BUFFER_SIZE 32

#define COPY_SUCCESS 0
#define COPY_ILLEGAL_ARGUMENTS (-1)
#define COPY_SRC_OPEN_ERROR (-2)
#define COPY_SRC_READ_ERROR (-3)
#define COPY_DEST_OPEN_ERROR (-4)
#define COPY_DEST_WRITE_ERROR (-5)
#define COPY_UNKNOWN_ERROR (-100)

#define ERROR_ILLEGAL_ARGUMENTS (-1)
#define ERROR_CANNOT_OPEN (-2)
#define ERROR_READ_FILE (-3)
#define ERROR_UNSUPPORTED_CHARSET (-99)

#define CHARSET_UTF8 0
#define CHARSET_GBK 1

#define DOWNLOAD_TASKS 5

#define SWAP(a, b, type) do{type tmp=a;a=b;b=tmp;}while(0)

/**
 * 注意项：
 *  1. 指针地址指向的值，做运算会变成右值
 *  2. 地址符号获取的地址值也不能作为左值
 *  3. 函数返回的只能是指针或值类型，不能返回数组类型
 *
 *  char s[10] = "abcdefg";
 *  printf("01. %x\n", &s); // 字符数组首项地址
 *
 *  printf("02. %x\n", s); // 指针的值->字符数组首项地址
 *  printf("03. %x\n", *(&s)); // 指向指针的地址->指针的值->字符数组首项地址
 *  printf("04. %x\n", &s[0]); // 字符数组首项地址
 *
 *  printf("05. %x\n", *s); // 指向指针的值->指向字符数组首项地址->字符数组首项值
 *  printf("06. %x\n", *(&s[0])); // 指向字符数组首项地址->字符数组首项值
 *  printf("07. %x\n", s[0]); // 字符数组首项值
 *
 * **/


void Reverse(char *arr, int length) {
    // 反转数组
    for (int i = 0; i < length / 2; ++i) {
        char tmp = arr[length - i - 1];
        arr[length - i - 1] = arr[i];
        arr[i] = tmp;
    }
}

int SafeRealloc(int useLength, int *length, int expansion, char **space) {
    if (expansion < 0) {
        return 0;
    }

    if (useLength + expansion >= *length) {
        if (expansion == 0) {
            *length *= 2;
        } else {
            *length += expansion;
        }
        void *newValue = realloc(*space, *length * sizeof(char));
        if (!newValue) {
            free(space);
            space = NULL;
            exit(1);
        }
        *space = newValue;
    }

    return 1;
}

void Bin(int num, char **saOutValue, int *outLength) {
    /**
     * 打印无符号整型二进制表示
     * char *binValue;
     * int length;
     * bin(4096, &binValue, &length);
     * printf("%d\n", length);
     * printf("%s\n", binValue);
     * free(binValue);
     * binValue = NULL;
     */
    int i = 0;
    int absNum = abs(num);
    int sValueLength = 8;
    char *sValue = malloc(sValueLength * sizeof(char));

    while (absNum != 0) { // 辗转相除
        char bit[1];
        itoa(absNum % 2, bit, 10);
        sValue[i] = bit[0];
        absNum >>= 1;
        i++;
        SafeRealloc(i, &sValueLength, 0, &sValue);
    }

    sValue[i] = '\0';
    Reverse(sValue, i);

    i += 3;
    *saOutValue = malloc(sizeof(char) * i);
    if (num >= 0) {
        sprintf(*saOutValue, "0b%s", sValue);
    } else {
        sprintf(*saOutValue, "-0b%s", sValue);
    }

    free(sValue);
    sValue = NULL;

    *outLength = i;
}

int IsBigEndian() {
    // 判断系统是否为大端序
    union {
        char c_[2];
        short s_;
    } value = {.s_=0x100};
    return value.c_[0];
}

int ToggleEndian(int original) {
    // 切换大端序和小端序
    union {
        char c_[4];
        int i_;
    } value = {.i_=original};

    // int的四个字节进行交换顺序，切换大端序和小端序
    char temp = value.c_[0];
    value.c_[0] = value.c_[3];
    value.c_[3] = temp;

    temp = value.c_[1];
    value.c_[1] = value.c_[2];
    value.c_[2] = temp;

    return value.i_;
}

typedef struct ListNode {
    int value;
    struct ListNode *next;
} ListNode;

ListNode *CreateNode(int value) {
    // 创建链表节点
    ListNode *node = malloc(sizeof(ListNode));
    if (!node) exit(1);
    node->value = value;
    node->next = NULL;
    return node;
}

void DestroyNode(ListNode **node_ptr) {
    // 销毁链表节点
    (*node_ptr)->next = NULL;
    free(*node_ptr);
    *node_ptr = NULL;
}

ListNode *CreateList(int array[], int length) {
    // 销毁链表数组
    if (length <= 0)return NULL;
    ListNode *head = CreateNode(array[0]);
    ListNode *current = head;
    for (int i = 1; i < length; ++i) {
        current->next = CreateNode(array[i]);
        current = current->next;
    }
    return head;
}

void DestroyList(ListNode **head) {
    // 销毁链表数组
    if (!head || !(*head))return;
    ListNode *current = *head;
    while (current) {
        current = current->next;
        DestroyNode(&current);
    }
    *head = NULL;
}

void InsertNode(ListNode **head, int index, int value) {
    // 插入链表节点
    if (!head || index < 0)return;
    ListNode *new_node = CreateNode(value);
    if (index == 0) {
        new_node->next = *head;
        *head = new_node;
    } else {
        if (!(*head)) {
            *head = CreateNode(0);
        }
        ListNode *current = *head;
        while (index > 1) {
            if (current->next) {
                current->next = CreateNode(0);
            }
            current = current->next;
            index--;
            new_node->next = current->next;
            current->next = new_node;
        }
    }
}

void SwapArray(int arr[], int l, int r) {
    int tmp = arr[l];
    arr[l] = arr[r];
    arr[r] = tmp;
}

void SwapInt(int *a, int *b) {
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

int LomutoPartition(int arr[], int low, int high) {
    /**
     * low          high
     * [1,8,4,2,7,6,{3}]
     * [1,2,[4],8,7,6,{3}] 找到第一个比high大的数字
     * [1,2,{3},8,7,6,4] 交换位置
     * @param arr
     * @param low
     * @param high
     * @return
     */
    int pivot = arr[high];
    int partition = low;
    for (int i = low; i < high; ++i) {
        if (arr[i] < pivot) {
            // 如果当前位置i数据比high位小则与partition交换位置并且partition向前移动
            SwapArray(arr, i, partition);
            partition++;
        }
    }
    // 交换切割位置
    SwapArray(arr, partition, high);
    // 返回切割位置
    return partition;
}

void LomutoQuickSort(int arr[], int low, int high) {
    /**
     * 快速排序，Lomuto分割法
     * https://blog.csdn.net/gaohuaid/article/details/9115567
     * @param ARR
     * @param low
     * @param high
     */
    if (low >= high)return;
    int position = LomutoPartition(arr, low, high);
    LomutoQuickSort(arr, low, position - 1);
    LomutoQuickSort(arr, position + 1, high);
}

int *HoarePartition(int *low, int *high) {
    int pivot = *(low + (high - low) / 2);
    int *p = low;
    int *q = high;
    while (1) {
        while (*p < pivot)p++; // 低位++
        while (*q > pivot)q--; // 高位--
        if (p >= q) break;
        SwapInt(p++, q--);
    }
    return q;
}

void HoareQuickSort(int *low, int *high) {
    /**
     * 快速排序，Hoare分割法
     * https://blog.csdn.net/qq_43632625/article/details/102995295
     * @param arr
     * @param low
     * @param high
     */
    if (low >= high)return;
    int *position = HoarePartition(low, high);
    HoareQuickSort(low, position);
    HoareQuickSort(position + 1, high);
}

void BubbleSort(int arr[], int length) {
    /**
     * 冒泡排序
     * @param arr
     * @param length
     */
    for (int i = 0; i < length; ++i) {
        for (int j = 0; j < length - 1 - i; ++j) {
            int next = j + 1;
            if (arr[j] > arr[next]) {
                SwapArray(arr, j, next);
            }
        }
    }
}

void ShuffleArray(int arr[], int length) {
    // 打乱数组
    srand(time(NULL));
    for (int i = length - 1; i > 0; --i) {
        int random_number = rand() % i;
        SwapArray(arr, i, random_number);
    }
}

void PrintPlatform(void) {
    puts(__FUNCTION__);

#ifdef __STDC_WANT_LIB_EXIT1__
    puts("support C11 safe version.");
#else
    puts("No supprot for C11 safe version.");
#endif

#ifdef __unix__
    puts("This is a Unix-like system");
#endif

#ifdef linux
    puts("This is a Linux system.");
#endif

#ifdef __APPLE__
    puts("This is Apple system.");
#endif

#ifdef _WIN32
    puts("This is windows system.");
#endif

#ifdef __STDC__
    puts("The compiler compiles to the ANSI standard");
    printf("ANSI Standard Version: %ld.\n", __STDC_VERSION__);
    printf("File name: %s.\n", __FILE__);
    printf("Number of execution lines: %u.\n", __LINE__);

#if defined(linux)
    printf("Current date: %s.\n", __DATE__);
    printf("Current time: %s.\n", __TIME__);
#endif

#if defined(_WIN32)
    printf("Current date: %u.\n", __DATE__);
    printf("Current time: %u.\n", __TIME__);
#endif
#endif

#ifdef __cplusplus
    puts("C++ environment");
#endif

//GCC编译器
#ifdef __GNUC__
#if __GNUC__ >= 3 // GCC3.0以上
#endif
#endif

//MSVC编译器
#ifdef _MSC_VER
#if _MSC_VER >= 1000 // VC++4.0以上
#if _MSC_VER >= 1100 // VC++5.0以上
#if _MSC_VER >= 1200 // VC++6.0以上
#if _MSC_VER >= 1300 // VC2003以上
#if _MSC_VER >= 1400 // VC2005以上
#if _MSC_VER >= 1500 // VC2008以上
#if _MSC_VER >= 1600 // VC2010以上
#if _MSC_VER >= 1700 // VC2012以上
#if _MSC_VER >= 1800 // VC2013以上
#if _MSC_VER >= 1900 // VC2015以上
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif

//Borland C++
#ifdef __BORLANDC__
#endif

//Cygwin
#ifdef __CYGWIN__
#ifdef __CYGWIN32__
#endif
#endif

//mingw
#ifdef __MINGW32__
#endif

//windows
#ifdef _WIN32    //32bit
#endif

#ifdef _WIN64    //64bit
#endif

#ifdef _WINDOWS     //图形界面程序
#endif

#ifdef _CONSOLE     //控制台程序
    // Windows（95/98/Me/NT/2000/XP/Vista）和Windows CE都定义了
#if (WINVER >= 0x030a)     // Windows 3.1以上
#if (WINVER >= 0x0400)     // Windows 95/NT4.0以上
#if (WINVER >= 0x0410)     // Windows 98以上
#if (WINVER >= 0x0500)     // Windows Me/2000以上
#if (WINVER >= 0x0501)     // Windows XP以上
#if (WINVER >= 0x0600)     // Windows Vista以上
    // _WIN32_WINNT 内核版本
#if (_WIN32_WINNT >= 0x0500) // Windows 2000以上
#if (_WIN32_WINNT >= 0x0501) // Windows XP以上
#if (_WIN32_WINNT >= 0x0600) // Windows Vista以上
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
#endif
}

void WtoC(const wchar_t *wcs, char *cs) {
    int size = (int) wcslen(wcs) + 1;
    for (int i = 0; i < size; ++i) {
        cs[i] = (char) wcs[i];
    }
}

void PrintWString(const wchar_t *content) {
#ifdef linux
    PRINTF_STR("%ls\n", content);
#endif

#ifdef _WIN32
    PRINTF_STR(L"%ls\n", content);
#endif
}

void HandleVarargsDemo(int arg_count, ...) {
    va_list args;
    va_start(args, arg_count);
    for (int i = 0; i < arg_count; ++i) {
        int arg = va_arg(args, int);
        printf("%d: %d\n", i, arg);
    }
}

void DynamicAllocationDemo(void) {
    // 动态分配内存即使函数退出也不会释放，需要手动释放
    // 注意指针变量会被回收，但是指向的地址必须手动回收
    int *players = malloc(sizeof(int) * 10);
    for (int i = 0; i < 10; ++i) {
        players[i] = i;
    }
    free(players);
    players = NULL;

    int *players_2 = calloc(10, sizeof(int));
    for (int i = 0; i < 10; ++i) {
        players_2[i] = i;
    }
    free(players_2);
    players_2 = NULL;
}

typedef void (*FunctionCallbackType)(char *);

typedef int Boolean;

void FunctionCallback(char *content) {
    printf("%s", content);
}

void FunctionCaller(FunctionCallbackType callback) {
    callback("Hello world");
}

void FunctionPointerDemo(void) {
    FunctionCallbackType fc = FunctionCallback;
    FunctionCaller(fc);
}

void StringDemo(void) {
    printf("%d\n", iscntrl(',')); // 检测一个字符是否是控制字符
    printf("%d\n", isprint(',')); // 判断一个字符是否是可打印字符
    printf("%d\n", isspace(' '));
    printf("%d\n", isblank(' '));
    printf("%d\n", isgraph(' ')); // 检测一个字符是否是图形字符
    printf("%d\n", ispunct(',')); // 判断一个字符是否是符号
    printf("%d\n", isalnum('f'));
    printf("%d\n", isalpha('a'));
    printf("%d\n", isupper('a'));
    printf("%d\n", islower('a'));
    printf("%d\n", isdigit('0'));
    printf("%d\n", isxdigit('0'));

    printf("%f\n", atof("12"));
    printf("%d\n", atoi("12"));
    printf("%ld\n", atol("12"));
    printf("%lld\n", atoll("12"));

    //  strtoll();
    //  strtoul();
    //  strtoull();
    //  strtof();
    //  strtod();
    //  strtold();
    //  strtoimax();
    //  strtoumax();
    char const *const kInput = "1 2000000 3 -4 5abcd bye0";
    char const *start = kInput;
    char *end;
    while (1) {
        errno = 0;
        const long kI = strtol(start, &end, 10);

        printf("null %x\n", end);

        if (start == end) {
            break;
        }

        printf("'%.*s'\t==> %ld.", (int) (end - start), start, kI);

        if (errno == ERANGE) {
            perror("");
        }

        putchar('\n');
        start = end;
    }
    printf("%s\n", end);

    // 比较字符串
    printf("%d\n", strncmp("hello", "hello2323", 5));

    char *demo_str_ptr = "Hello World!";
    char *result = strchr(demo_str_ptr, 'l');
    char *result_reverse = strrchr(demo_str_ptr, 'l');
    puts(result);
    puts(result_reverse);

    char *demo_str_2_ptr = "C, 1972; C++, 1983; Java, 1995; Rust, 2010; Kotlin, 2011";
    char *break_set = ",;";
    char *p = demo_str_2_ptr;
    do {
        p = strpbrk(p, break_set);
        if (p) {
            puts(p);
            p++;
        }
    } while (p);

    char *substring = strstr(demo_str_2_ptr, "C++");
    puts(substring);

    char demo_str_3_ptr[] = "C, 1972; C++, 1983; Java, 1995; Rust, 2010; Kotlin, 2011";
    typedef struct {
        char *name_;
        int year_;
    } Language;
    const char *language_break = ";";
    const char *field_break = ",";
    int language_capacity = 3;
    int language_size = 0;
    Language *languages = malloc(sizeof(Language) * language_capacity);
    if (!languages) {
        abort();
    }
    char *next = strtok(demo_str_3_ptr, field_break);
    while (next) {
        Language language;
        language.name_ = next;
        next = strtok(NULL, language_break);
        if (next) {
            language.year_ = atoi(next);
            if (language_size + 1 >= language_capacity) {
                language_capacity *= 2;
                languages = realloc(languages, sizeof(Language) * language_capacity);
                if (!languages) {
                    abort();
                }
            }
            languages[language_size++] = language;
            next = strtok(NULL, field_break);
        }
    }
    free(languages);
    languages = NULL;

    char src[] = "Hello";
    char dest[20] = " World";
    // strcat(dest, src); // 追加字符串
    strcpy(dest + strlen(dest), src); // 复制字符串
    printf("%s", dest);
}

void WideConvertDemo(void) {
    char mbs[] = "你好";
    wchar_t wcs[10];
    mbstowcs(wcs, mbs, 10); // mingw64转换会错误，utf8支持差
    PrintWString(wcs);
}

long long TimeInMillisecond(void) {
    // 获取当前时间的毫秒为单位的时间戳
#if defined(_WIN32)
    struct timeb time_buffer;
    ftime(&time_buffer);
    return time_buffer.time * 1000LL + time_buffer.millitm;
#elif defined(__unix__) || defined(__APPLE__)
    struct timeval time_value;
    gettimeofday(&time_value, NULL);
    return time_value.tv_sec * 1000LL + time_value.tv_usec / 1000;
#elif defined(__STDC__) && __STDC_VERSION__ == 201112L
    struct timespec timespec_value;
    timespec_get(&timespec_value, TIME_UTC);
    return timespec_value.tv_sec * 1000LL + timespec_value.tv_nsec / 1000000;
#else
    return time(NULL) * 1000;
#endif
}

void TimeDemo(void) {
    time_t current_time;
    time(&current_time);
    printf("%ld\n", current_time); // 时间戳精确到秒

    long long current_time2 = TimeInMillisecond();
    printf("%lld\n", current_time2);
}

void CalendarTimeDemo(void) {
    time_t current_time;
    time(&current_time);

    struct tm *gmt = gmtime(&current_time); // 格林威治时间
    printf("%d\n", gmt->tm_year);
    printf("%d\n", gmt->tm_mon);
    printf("%d\n", gmt->tm_mday);
    printf("%d\n", gmt->tm_hour);
    printf("%d\n", gmt->tm_min);
    printf("%d\n", gmt->tm_sec);

    struct tm *calender_time = localtime(&current_time); // 本地时区时间
    printf("%d\n", calender_time->tm_year);
    printf("%d\n", calender_time->tm_mon);
    printf("%d\n", calender_time->tm_mday);
    printf("%d\n", calender_time->tm_hour);
    printf("%d\n", calender_time->tm_min);
    printf("%d\n", calender_time->tm_sec);

    time_t current_time_2 = mktime(calender_time); // 修改calender_time需要使用mktime完成进位
    printf("%d\n", current_time_2);

    puts(asctime(calender_time));

    puts(ctime(&current_time));

    char current_time_str[20];
    size_t size = strftime(current_time_str, 20, "%Y-%m-%d %H:%M:%S", calender_time);
    printf("%d\n", size);
    printf("%s\n", current_time_str);

#ifdef linux
    PrintWString(L"linux平台支持解析时间");
    struct tm parsed_time;
    char *unparsed_str = strptime(current_time_str, "%F %T", &parsed_time);
    printf("%s\n", unparsed_str);
    printf("%d\n", calender_time->tm_year);
    printf("%d\n", calender_time->tm_mon);
    printf("%d\n", calender_time->tm_mday);
    printf("%d\n", calender_time->tm_hour);
    printf("%d\n", calender_time->tm_min);
    printf("%d\n", calender_time->tm_sec);
#endif

    char dot_str[] = ".123";
    int number;
    sscanf(dot_str, ".%3d", &number);
    printf("%d\n", number);

    time_t start_time = time(NULL);
    time_t end_time = time(NULL);
    double diff = difftime(start_time, end_time);
    printf("diff: %f\n", diff);

    clock_t start_time_c = clock(); // 程序运行时间
    TimeDemo();
    clock_t end_time_c = clock();
    printf("clock diff: %f\n", (end_time_c - start_time_c) * 1.0 / CLOCKS_PER_SEC);
}

void GetCharDemo(void) {
    while (1) {
        int next_input = getchar(); // fgetc(stdin) getc(stdin)
        if (next_input == EOF) { // ctrl+z输出EOF
            break;
        } else if (next_input == '\n') {
            continue;
        }
        putchar(next_input);
    }
}

void GetCharDemo2(void) {
#if defined(__STDC__) && __STDC_VERSION__ < 201112L
    char buffer[1024];
    while (1) {
        if (!fgets(buffer, 1024, stdin)) { // fgets会有换行符存在
            break;
        }
        // puts("echo: ");
        // puts(buffer);
        printf("%s", buffer);
    }
#else
    char buffer[1024];
    while (1) {
      if (!gets_s(buffer, 1024)) {
        break;
      }
      puts(buffer);
    }
#endif

}

void GetCharDemo3(void) {
    char buffer[BUFFER_SIZE];
    while (1) {
        size_t bytes_read = fread(buffer, sizeof(char), BUFFER_SIZE, stdin);
        if (bytes_read < BUFFER_SIZE) {
            if (feof(stdin)) {
                puts("EOF");
                fwrite(buffer, sizeof(char), bytes_read, stdout);
            } else if (ferror(stdin)) {
                perror("Error read from");
            }
            break;
        }

        fwrite(buffer, sizeof(char), BUFFER_SIZE, stdout);
    }
}

int MyCopyFile1(char const *src, char const *dest) {
    // 按字符复制
    if (!src || !dest) {
        return COPY_ILLEGAL_ARGUMENTS;
    }

    FILE *src_file = fopen(src, "rb");
    if (!src_file) {
        return COPY_SRC_OPEN_ERROR;
    }

    FILE *dest_file = fopen(dest, "wb");
    if (!dest_file) {
        fclose(src_file);
        return COPY_DEST_OPEN_ERROR;
    }

    int result;
    while (1) {
        int next = fgetc(src_file);
        if (next == EOF) {
            if (ferror(src_file)) {
                result = COPY_SRC_READ_ERROR;
            } else if (feof(src_file)) {
                result = COPY_SUCCESS;
            } else {
                result = COPY_UNKNOWN_ERROR;
            }
            break;
        }

        if (fputc(next, dest_file) == EOF) {
            result = COPY_DEST_WRITE_ERROR;
            break;
        }
    }

    fclose(src_file);
    fclose(dest_file);

    return result;
}

int MyCopyFile2(char const *src, char const *dest) {
    // 按行复制
    if (!src || !dest) {
        return COPY_ILLEGAL_ARGUMENTS;
    }

    FILE *src_file = fopen(src, "r");
    if (!src_file) {
        return COPY_SRC_OPEN_ERROR;
    }

    FILE *dest_file = fopen(dest, "w");
    if (!dest_file) {
        fclose(src_file);
        return COPY_DEST_OPEN_ERROR;
    }

    int result;
    char buffer[BUFSIZ];
    char *next;

    while (1) {
        next = fgets(buffer, BUFSIZ, src_file);
        if (!next) {
            if (ferror(src_file)) {
                result = COPY_SRC_READ_ERROR;
            } else if (feof(src_file)) {
                result = COPY_SUCCESS;
            } else {
                result = COPY_UNKNOWN_ERROR;
            }
            break;
        }

        if (fputs(next, dest_file) == EOF) {
            result = COPY_DEST_WRITE_ERROR;
            break;
        }
    }

    fclose(src_file);
    fclose(dest_file);

    return result;
}

int MyCopyFile3(char const *src, char const *dest) {
    // 任意大小复制
    if (!src || !dest) {
        return COPY_ILLEGAL_ARGUMENTS;
    }

    FILE *src_file = fopen(src, "rb");
    if (!src_file) {
        return COPY_SRC_OPEN_ERROR;
    }

    FILE *dest_file = fopen(dest, "wb");
    if (!dest_file) {
        fclose(src_file);
        return COPY_DEST_OPEN_ERROR;
    }

    int result = COPY_SUCCESS;
    char buffer[BUFSIZ];

    while (1) {
        size_t bytes_read = fread(buffer, sizeof(buffer[0]), BUFSIZ, src_file);

        if (fwrite(buffer, sizeof(buffer[0]), bytes_read, dest_file) < bytes_read) {
            result = COPY_DEST_WRITE_ERROR;
            break;
        }

        if (bytes_read < BUFFER_SIZE) {
            if (ferror(src_file)) {
                result = COPY_SRC_READ_ERROR;
            } else if (feof(src_file)) {
                result = COPY_SUCCESS;
            } else {
                result = COPY_UNKNOWN_ERROR;
            }
            break;
        }
    }

    fclose(src_file);
    fclose(dest_file);

    return result;
}

void IODemo(void) {
    FILE *file = fopen("demo.txt", "r");

    // 设置缓冲区
    // char buf[BUFSIZ];// DMA 区域缓冲，BUFSIZ建议设置8192，缓冲区要比IO生命周期长
    if (file) {
        int err = ferror(file);
        int eof = feof(file);
        puts("Open successfully.");
        // setbuf(file, buf);
        // setvbuf(file, buf, _IOLBF, BUFSIZ); // 按行缓冲

        int next_char = getc(file);
        while (next_char != EOF) {
            putchar(next_char);
            next_char = getc(file);
        }

        // fflush(stdout); // 清空缓冲区
        fclose(file);
    } else {
        printf("%d ", errno);
        puts(strerror(errno));
        perror("fopen");
    }

    // freopen("output.log", "a", stdout); // 重定向标准输入流到文件
    // fclose(stdout);

#ifdef __STDC__
#endif
}

void RedirectStdout(char const *filename) {
    static int saved_stdout_no = -1;

    if (filename) {
        if (saved_stdout_no == -1) {
            saved_stdout_no = dup(fileno(stdout)); // 保存标准输出描述符
            fflush(stdout);
            freopen(filename, "a", stdout);
        }
    } else {
        if (saved_stdout_no != -1) {
            dup2(saved_stdout_no, fileno(stdout)); // 恢复标准输出重定向
            close(saved_stdout_no);
            saved_stdout_no = -1;
        }
    }
}

int CountCharactersInFile(char const *filename, int charset) {
    if (!filename) return ERROR_ILLEGAL_ARGUMENTS;

    FILE *file;
    switch (charset) {
        case CHARSET_GBK:
#ifdef _WIN32
            setlocale(LC_ALL, "chs");
#else
            setlocale(LC_ALL, "zh_CN.gbk");
#endif
            file = fopen(filename, "r");
            break;
        case CHARSET_UTF8:
            setlocale(LC_ALL, "zh_CN.utf-8");
#ifdef _WIN32
            file = fopen(filename, "r,css=utf-8");
#else
            file = fopen(filename, "r");
#endif
            break;
        default:
            return ERROR_UNSUPPORTED_CHARSET;
    }

    if (!file)return ERROR_CANNOT_OPEN;

    wchar_t wcs[BUFSIZ];
    int count = 0;
    while (fgetws(wcs, BUFSIZ, file)) {
        count += wcslen(wcs);
    }

    if (ferror(file)) {
        perror("CountCharactersInFile error");
        fclose(file);
        return ERROR_READ_FILE;
    }

    fclose(file);
    return count;
}

void FileDemo(void) {
    FILE *file = fopen("demo.txt", "rb");
    long position = ftell(file);
    printf("%ld", position);

    char buffer[BUFSIZ];
    fread(buffer, 1, BUFSIZ, file);
    printf("%ld", ftell(file));

    // fseek(file, 10, SEEK_SET); // 相对于文件流开头偏移
    // fseek(file, 10, SEEK_CUR); // 相对于文件流当前偏移
    // fseek(file, 10, SEEK_END); // 相对于文件流底部偏移

    // fsetpos(); // 宽字符位置设置
    // fgetpos(); // 宽字符位置获取

    fclose(file);

    // remove("") // 删除文件
    // rename() // 重命名
    // FILE *tmp_file = tmpfile(); // 创建临时文件
    // tmpnam() // 获取临时文件路径
}

long MyGetFileSize(char const *filename) {
    struct stat st;
    stat(filename, &st);
    return st.st_size;
}

int IsDirectory(char const *filename) {
    struct stat st;
    stat(filename, &st);
    return st.st_mode & S_IFDIR;
}

int SayHello(char *name) {
    printf("Hello, %s\n", name);
    return 0;
}

volatile int flag = 0; // 防止编译优化变量产生重排序，禁止编译器优化读写操作，msvc是强制刷新缓存，保证可见性
atomic_int a = 0; // 原子类型

void ThreadDemo(void) {
    thrd_t thread_1;

    int result = thrd_create(&thread_1, (thrd_start_t) SayHello, "C Lang");
    if (result == thrd_success) {
        printf("Run in Main thread[%#x], created thread_1[%#x]\n", thrd_current(), thread_1);
    } else {
        printf("Run in Main thread[%#x], failed to create thread_1\n", thrd_current());
    }
    // thrd_sleep(&(struct timespec) {.tv_sec=0, .tv_nsec=100000000}, NULL);

    int res;
    thrd_join(thread_1, &res);
    printf("%d\n", res);

    // thrd_detach(thread_1); // 和join互斥，不等线程执行结果，让它运行完之后自动销毁

    // thrd_yield();
}

atomic_flag resume_flag = ATOMIC_FLAG_INIT; // CPU指令无锁实现的原子操作

int PrintNumbers(void *arg) {
    int current = 0;
    while (atomic_flag_test_and_set(&resume_flag)) {
        current++;
        printf("Current: %d\n", current);

        thrd_sleep(&(struct timespec) {.tv_sec=1}, NULL);
    }
    return current;
}

void AtomicDemo(void) {
    atomic_flag_test_and_set(&resume_flag);

    thrd_t t;
    thrd_create(&t, PrintNumbers, NULL);

    thrd_sleep(&(struct timespec) {.tv_sec=5}, NULL);

    atomic_flag_clear(&resume_flag);

    int last_number;
    thrd_join(t, &last_number);
    printf("%d", last_number);
}

int count = 0;
mtx_t mutex;

int Counter(void *arg) {
    for (int i = 0; i < 1000000; ++i) {
        mtx_lock(&mutex);
        count++;
        mtx_unlock(&mutex);
    }
}

void LockDemo(void) {
    mtx_init(&mutex, mtx_plain);

    thrd_t t_1, t_2;
    thrd_create(&t_1, Counter, NULL);
    thrd_create(&t_2, Counter, NULL);

    thrd_join(t_1, NULL);
    thrd_join(t_2, NULL);

    printf("%d\n", count);
    mtx_destroy(&mutex);
}

_Thread_local int local_count = 0; // 线程存储变量，每个线程有独立副本，线程开始创建，结束销毁
tss_t count_key; // 线程存储器

void MyFree(void *ptr) {
    free(ptr);
}

int LocalCounter(const int *step) {
    // 动态内存Local化
    int *_count = malloc(sizeof(int));
    *_count = 0;
    if (tss_set(count_key, _count) == thrd_success) {
        for (int i = 0; i < 1000000; ++i) {
            *_count += *step;
        }
    }

    printf("%d", tss_get(count_key));
    return 0;
}

void LocalDemo(void) {
    if (tss_create(&count_key, MyFree) == thrd_success) {
        thrd_t t_1, t_2;
        int step_1 = 1, step_2 = 2;
        thrd_create(&t_1, LocalCounter, &step_1);
        thrd_create(&t_2, LocalCounter, &step_2);

        thrd_join(t_1, NULL);
        thrd_join(t_2, NULL);

        printf("%d\n", count);

        tss_delete(count_key); // 如果线程结束时已经调用tss_delete，则不会执行释放
    }
}

void SleepMs(long milliseconds) {
    long seconds = milliseconds / 1000;
    long nanoseconds = (milliseconds % 1000) * 1000000L;
    thrd_sleep(&(struct timespec) {.tv_sec=seconds, .tv_nsec=nanoseconds}, NULL);
}

typedef struct Context {
    mtx_t mutex;
    int download_left;
} Context;

typedef struct DownloadRequest {
    Context *context;
    char const *url;
    char const *filename;
    int progress;
    int interval;

    void (*callback)(struct DownloadRequest *);
} DownloadRequest;

int DownloadFile(DownloadRequest *request) {
    printf("\rDownloading file from: %s into %s ...", request->url, request->filename);

    for (int i = 0; i < 100; ++i) {
        request->progress = i;
        SleepMs(request->interval);
    }

    request->callback(request);
    return 0;
}

void DownloadCallback(DownloadRequest *request) {
    mtx_lock(&request->context->mutex);
    request->context->download_left--;
    printf(
            "\rDownload file from: %s into %s successfully, left: %d",
            request->url,
            request->filename,
            request->context->download_left
    );

    mtx_unlock(&request->context->mutex);
}

void DownLoadDemo(void) {
    char *urls[] = {
            "https://www.bennyhuo.com/file1",
            "https://www.bennyhuo.com/file2",
            "https://www.bennyhuo.com/file3",
            "https://www.bennyhuo.com/file4",
            "https://www.bennyhuo.com/file5",
    };

    char *filenames[] = {
            "download/file1",
            "download/file2",
            "download/file3",
            "download/file4",
            "download/file5",
    };

    DownloadRequest requests[DOWNLOAD_TASKS];
    Context context = {.download_left = DOWNLOAD_TASKS};
    mtx_init(&context.mutex, mtx_plain);

    for (int i = 0; i < DOWNLOAD_TASKS; ++i) {
        requests[i] = (DownloadRequest) {
                .context = &context,
                .url = urls[i],
                .filename = filenames[i],
                .progress = 0,
                .interval = i * 50 + 100,
                .callback = DownloadCallback
        };

        thrd_t t;
        thrd_create(&t, DownloadFile, &requests[i]);
        thrd_detach(t);
    }

    while (1) {
        mtx_lock(&context.mutex);
        int download_left = context.download_left;
        mtx_unlock(&context.mutex);
        if (download_left == 0) {
            break;
        }

        printf("\r");

        for (int i = 0; i < DOWNLOAD_TASKS; ++i) {
            printf("%s -- %3d%% \t", requests[i].filename, requests[i].progress);
        }

        fflush(stdout);
        SleepMs(100);
    }

    mtx_destroy(&context.mutex);
}

int main(void) {
    ENCODING_UTF_8;
    printf("%s", "Hello, C/C++");
    return 0;
}
